﻿using InTheHand.Net.Sockets;
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Sharpimeter.Model
{
    public class Mode8 : IMode
    {

        BluetoothClient Client;
        Stream PeerStream;
        public OnyxII Onyx;

        public Mode8(BluetoothClient cli, OnyxII onyx)
        {
            this.Client = cli;
            this.Onyx = onyx;
        }

        public void read()
        {
            List<OnyxReading> result = new List<OnyxReading>();
            this.PeerStream = this.Client.GetStream();
            if (InitRequest())
            {
                Byte[] sResponse;
                this.Onyx.OnStartReading();
                int noFinger = 0; // no finger count

                while (true)
                {
                    sResponse = new Byte[4]; // Reset response 
                    this.PeerStream.Read(sResponse, 0, 4);
                    if (this.emptyReading(sResponse))
                    {
                        break;
                    }
                    else if (this.sensorAlarm(sResponse))
                    {
                        noFinger++; // no finger count
                        Console.WriteLine("No finger detected " + noFinger);
                    }
                    else
                    {
                        noFinger = 0; // reset no finger count
                        if (ExtractLowBat(sResponse))
                        {
                            Console.WriteLine("Low Battery");
                        }

                        this.Onyx.OnReading(
                            new OnyxReading(DateTime.Now, this.ExtractPulse(sResponse), this.ExtractO2(sResponse), this.ExtractQuality(sResponse))    
                        );
                    }
                }
            }
            else
            {
                System.Diagnostics.Debug.WriteLine("Received NAK! Not good...");
            }

            this.Onyx.OnEndReading();
        }

        private bool InitRequest()
        {
            // Send data to use mode 8
            Byte[] byteStream = new Byte[] { 0x02, 0x70, 0x02, 0x02, 0x08, 0x03 };
            this.PeerStream.Write(byteStream, 0, byteStream.Length);

            // Wait for answer
            Byte[] ack = new Byte[1];
            this.PeerStream.Read(ack, 0, 1);

            // return true or false
            return (ack[0] == 0x06);
        }

        private bool emptyReading(byte[] reading)
        {
            if (reading[0] == 0 && reading[1] == 0 && reading[2] == 0 && reading[3] == 0)
            {
                return true;
            }
            return false;
        }

        /* isBitSet
         * data is a byte, position from right to left start at 0 to 7
         * return true or false
         */
        private bool isBitSet(byte data, int position)
        {
            // data bitwise and, shift the 1 to corret position
            return ((data & (1 << position)) > 0);
        }

        public void endRead()
        {
            
        }

        // read from byte 1 and bit 1 & 2 from byte 0
        private int ExtractPulse(byte[] data)
        {
            int pulse = Convert.ToInt32(data[1]);
            if (isBitSet(data[0], 1))
            {
                pulse += 128;
            }
            if (isBitSet(data[0], 2))
            {
                pulse += 256;
            }
            return pulse;
        }

        // read from byte 2
        private int ExtractO2(byte[] data)
        {
            return Convert.ToInt32(data[2]);
        }

        // read from bit 0 in byte 3
        private bool ExtractLowBat(byte[] data)
        {
            return isBitSet(data[3], 0); 
        }

        // read from bit 3 in byte 3
        private bool sensorAlarm(byte[] data)
        {
            return isBitSet(data[3], 3);
        }

        // read from bit 5 in byte 3
        private bool ExtractQuality(byte[] data)
        {
            return isBitSet(data[3], 5);
        }
    }
}
